home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / disk.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  15KB  |  641 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Floppy disk emulation
  5.   *
  6.   * (c) 1995 Bernd Schmidt, Hannu Rummukainen
  7.   */
  8.  
  9. #include <stdio.h>
  10.  
  11. #include "sysconfig.h"
  12. #include "sysdeps.h"
  13.  
  14. #include "config.h"
  15. #include "options.h"
  16. #include "threaddep/penguin.h"
  17. #include "memory.h"
  18. #include "gensound.h"
  19. #include "sounddep/sound.h"
  20. #include "events.h"
  21. #include "custom.h"
  22. #include "ersatz.h"
  23. #include "disk.h"
  24. #include "gui.h"
  25. #include "zfile.h"
  26. #include "autoconf.h"
  27. #include "readcpu.h"
  28. #include "newcpu.h"
  29. #include "xwin.h"
  30. #include "osemu.h"
  31. #include "execlib.h"
  32.  
  33. #define FLOPPY_GAP_LEN 360
  34.  
  35. #define FLOPPY_SPEED 4
  36.  
  37. uae_u16* mfmwrite;
  38. static uae_u16 mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */
  39.  
  40. static int side, direction, step;
  41. static uae_u8 selected = 15;
  42. static int dskready;
  43.  
  44. typedef struct {
  45.     uae_u16 sync;
  46.     uae_u16 len;
  47.     uae_u32 offs;
  48. } trackid;
  49.  
  50. #define MAX_TRACKS 328
  51.  
  52. typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype;
  53. typedef struct {
  54.     FILE *diskfile;
  55.     drive_filetype filetype;
  56.     trackid trackdata[MAX_TRACKS];
  57.     unsigned int buffered_cyl, buffered_side;
  58.     unsigned int cyl;
  59.     int side;
  60.     int motoroff;
  61.     int wrprot;
  62.     uae_u16 bigmfmbuf[0x4000];
  63.     int tracklen;
  64.     unsigned long last_cycles;
  65.     int mfmpos;
  66.     unsigned int num_tracks, num_secs;
  67.     /* dskchange is set to a small number when a disk is removed. At a step
  68.      * impulse, it is reset if there is a new disk in the drive or counted
  69.      * down to 1 if the drive contains a disk. DISK_check_change will only
  70.      * insert a new disk when dskchange is 1, or if the dskchange_time timer
  71.      * expires. The last condition can happen if AmigaOS isn't running and a
  72.      * game/demo doesn't use the step motor to check for a new disk.
  73.      */
  74.     int dskchange;
  75.     int dskchange_time;
  76. } drive;
  77.  
  78. drive floppy[4];
  79.  
  80. static void drive_fill_bigbuf(drive *drv);
  81.  
  82. FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
  83. {
  84.     FILE *f = zfile_open(fname, "r+b");
  85.     if (f) {
  86.     if (wrprot)
  87.         *wrprot = 0;
  88.     } else {
  89.     if (wrprot)
  90.         *wrprot = 1;
  91.     f = zfile_open(fname, "rb");
  92.     }
  93.     if (!leave_open)
  94.     fclose (f);
  95.     return f;
  96. }
  97.  
  98. static int drive_insert(drive *drv, int dnum, const char *fname)
  99. {
  100.     unsigned char buffer[10];
  101.  
  102.     drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
  103.     if (drv->diskfile == 0)
  104.     return 0;
  105.  
  106.     strncpy (currprefs.df[dnum], fname, 255);
  107.     currprefs.df[dnum][255] = 0;
  108.     strncpy (changed_prefs.df[dnum], fname, 255);
  109.     changed_prefs.df[dnum][255] = 0;
  110.     gui_filename(dnum, fname);
  111.  
  112.     fread(buffer, sizeof(char), 8, drv->diskfile);
  113.     if (strncmp((char *)buffer,"UAE--ADF",8) == 0) {
  114.     int offs = 160*4+8;
  115.     int i;
  116.  
  117.     drv->filetype = ADF_EXT1;
  118.     drv->num_tracks = 160;
  119.     drv->num_secs = 11;
  120.  
  121.     drv->wrprot = 1; /* write to adf_ext1 not implemented */
  122.     for(i=0; i<160; i++) {
  123.         fread(buffer, 4, 1, drv->diskfile);
  124.         drv->trackdata[i].sync = buffer[0]*256 + buffer[1];
  125.         drv->trackdata[i].len = buffer[2]*256 + buffer[3];
  126.         drv->trackdata[i].offs = offs;
  127.         offs += drv->trackdata[i].len;
  128.     }
  129.     } else {
  130.     unsigned int i;
  131.  
  132.     drv->filetype = ADF_NORMAL;
  133.  
  134.     fseek(drv->diskfile,0,SEEK_END);
  135.     i = ftell(drv->diskfile);
  136.     fseek(drv->diskfile,0,SEEK_SET);
  137.  
  138.     /* High-density disk? */
  139.     if (i >= 160*22*512)
  140.         drv->num_tracks = i / (512*(drv->num_secs = 22));
  141.     else
  142.         drv->num_tracks = i / (512*(drv->num_secs = 11));
  143.  
  144.     if (drv->num_tracks > MAX_TRACKS)
  145.         write_log ("Your diskfile is too big!\n");
  146.     for(i = 0; i < drv->num_tracks; i++) {
  147.         drv->trackdata[i].len = 512 * drv->num_secs;
  148.         drv->trackdata[i].sync = 0;
  149.         drv->trackdata[i].offs = i * 512 * drv->num_secs;
  150.     }
  151.     }
  152.     drv->buffered_side = 2; /* will force read */
  153.     return 1;
  154. }
  155.  
  156. static int drive_empty(drive *drv)
  157. {
  158.     return drv->diskfile == 0;
  159. }
  160.  
  161. static void drive_step(drive *drv)
  162. {
  163.     if (!drive_empty(drv))
  164.     drv->dskchange = 0;
  165.     else if (drv->dskchange > 1) {
  166. /*    printf("Stepping...\n");
  167.     drv->dskchange--;*/
  168.     }
  169.     if (direction) {
  170.     if (drv->cyl) drv->cyl--;
  171.     } else {
  172.     if (drv->cyl < drv->num_tracks/2) drv->cyl++;
  173.     }
  174. }
  175.  
  176.  
  177. static int drive_track0(drive *drv)
  178. {
  179.     return drv->cyl == 0;
  180. }
  181.  
  182. static int drive_writeprotected(drive *drv)
  183. {
  184.     return drv->wrprot || drv->diskfile == NULL;
  185. }
  186.  
  187. static int drive_running(drive *drv)
  188. {
  189.     return !drv->motoroff;
  190. }
  191.  
  192. static void drive_motor(drive *drv, int off)
  193. {
  194.     if (drv->motoroff && !off) {
  195.     drv->last_cycles = cycles;
  196.     drv->mfmpos = 0;
  197.     eventtab[ev_diskindex].active = 1;
  198.     if (drv->tracklen)
  199.         eventtab[ev_diskindex].evtime = FLOPPY_SPEED * drv->tracklen + cycles;
  200.     else
  201.         eventtab[ev_diskindex].evtime = cycles + 1000;
  202.     eventtab[ev_diskindex].oldcycles = cycles;
  203.     } else if (off)
  204.     eventtab[ev_diskindex].active = 0;
  205.     drv->motoroff = off;
  206.     events_schedule();
  207. }
  208.  
  209. static void drive_fill_bigbuf(drive *drv)
  210. {
  211.     int tr = drv->cyl*2 + side;
  212.  
  213.     if (!drv->diskfile) {
  214.     drv->tracklen = 10;
  215.     memset (drv->bigmfmbuf,0xaa,drv->tracklen*2);
  216.     return;
  217.     }
  218.     if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
  219.     return;
  220.  
  221. /*    if (drv->num_tracks <= tr) {
  222.     write_log ("Access beyond end of floppy image!\n");
  223.     }*/
  224.     
  225.     if (drv->trackdata[tr].sync == 0) {
  226.     /* Normal AmigaDOS format track */
  227.     unsigned int sec;
  228.     drv->tracklen = drv->num_secs*544 + FLOPPY_GAP_LEN;
  229.     memset(drv->bigmfmbuf,0xaa,FLOPPY_GAP_LEN*2);
  230.  
  231.     for (sec = 0; sec < drv->num_secs; sec++) {
  232.         uae_u8 secbuf[544];
  233.         int i;
  234.         uae_u16 *mfmbuf = drv->bigmfmbuf + 544*sec + FLOPPY_GAP_LEN;
  235.         uae_u32 deven,dodd;
  236.         uae_u32 hck=0,dck=0;
  237.  
  238.         secbuf[0] = secbuf[1] = 0x00;
  239.         secbuf[2] = secbuf[3] = 0xa1;
  240.         secbuf[4] = 0xff;
  241.         secbuf[5] = tr;
  242.         secbuf[6] = sec;
  243.         secbuf[7] = drv->num_secs-sec;
  244.  
  245.         for(i = 8; i < 24; i++)
  246.         secbuf[i] = 0;
  247.  
  248.         fseek(drv->diskfile,
  249.           drv->trackdata[tr].offs + sec*512,
  250.           SEEK_SET);
  251.         fread(&secbuf[32],1,512,drv->diskfile);
  252.  
  253.         mfmbuf[0] = mfmbuf[1] = 0xaaaa;
  254.         mfmbuf[2] = mfmbuf[3] = 0x4489;
  255.  
  256.         deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
  257.              | (secbuf[6] << 8) | (secbuf[7]));
  258.         dodd = deven >> 1;
  259.         deven &= 0x55555555; dodd &= 0x55555555;
  260.  
  261.         mfmbuf[4] = dodd >> 16;
  262.         mfmbuf[5] = dodd;
  263.         mfmbuf[6] = deven>> 16;
  264.         mfmbuf[7] = deven;
  265.  
  266.         for (i = 8; i < 48; i++)
  267.         mfmbuf[i] = 0;
  268.         for (i = 0; i < 512; i += 4){
  269.         deven = ((secbuf[i+32] << 24) | (secbuf[i+33] << 16)
  270.              | (secbuf[i+34] << 8) | (secbuf[i+35]));
  271.         dodd = deven >> 1;
  272.         deven &= 0x55555555; dodd &= 0x55555555;
  273.         mfmbuf[(i>>1)+32] = dodd >> 16;
  274.         mfmbuf[(i>>1)+33] = dodd;
  275.         mfmbuf[(i>>1)+256+32] = deven >> 16;
  276.         mfmbuf[(i>>1)+256+33] = deven;
  277.         }
  278.  
  279.         for(i = 4; i < 24; i += 2)
  280.         hck ^= (mfmbuf[i] << 16) | mfmbuf[i+1];
  281.  
  282.         deven = dodd = hck; dodd >>= 1;
  283.         mfmbuf[24] = dodd >> 16; mfmbuf[25] = dodd;
  284.         mfmbuf[26] = deven>> 16; mfmbuf[27] = deven;
  285.  
  286.         for(i = 32; i < 544; i += 2)
  287.         dck ^= (mfmbuf[i] << 16) | mfmbuf[i+1];
  288.  
  289.         deven = dodd = dck; dodd >>= 1;
  290.         mfmbuf[28] = dodd >> 16; mfmbuf[29] = dodd;
  291.         mfmbuf[30] = deven>> 16; mfmbuf[31] = deven;
  292.     }
  293.     } else {
  294.     int i;
  295.     drv->tracklen = drv->trackdata[tr].len/2 + 1;
  296.     drv->bigmfmbuf[0] = drv->trackdata[tr].sync;
  297.     fseek(drv->diskfile, drv->trackdata[tr].offs, SEEK_SET);
  298.     fread((char *)(drv->bigmfmbuf + 1), 1, drv->trackdata[tr].len, drv->diskfile);
  299.     for (i = 0; i < drv->trackdata[tr].len/2; i++) {
  300.         uae_u16 *mfm = drv->bigmfmbuf + i + 1;
  301.         uae_u8 *data = (uae_u8 *)mfm;
  302.  
  303.         *mfm = 256 * *data + *(data+1);
  304.     }
  305.     }
  306.     drv->buffered_side = side;
  307.     drv->buffered_cyl = drv->cyl;
  308.     drv->last_cycles = cycles;
  309.     drv->mfmpos = 0;
  310. }
  311.  
  312. static int drive_get_data(drive *drv, uae_u16 *mfm, uae_u16 *byt)
  313. {
  314.     int offset,mfmpos;
  315.  
  316.     drive_fill_bigbuf(drv);
  317.     offset = (cycles - drv->last_cycles) / FLOPPY_SPEED;
  318.     mfmpos = (drv->mfmpos + offset) % drv->tracklen;
  319.     drv->last_cycles += offset*FLOPPY_SPEED;
  320.     drv->mfmpos = mfmpos;
  321.     *mfm = drv->bigmfmbuf[mfmpos];
  322.     return offset > 0;
  323. }
  324.  
  325. #define MFMMASK 0x55555555
  326. static __inline__ uae_u32 getmfmlong(uae_u16* mbuf)
  327. {
  328.     return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
  329. }
  330.  
  331. static void drive_write_data(drive *drv, uae_u16 *mbuf, int length)
  332. {
  333.     int i, secwritten = 0;
  334.     uae_u32 odd, even, chksum, id, dlong;
  335.     uae_u8* secdata;
  336.     uae_u8 secbuf[544];
  337.     uae_u16 *mend = mbuf + length;
  338.  
  339.     if (drive_writeprotected(drv))
  340.     return;
  341.  
  342.     drive_fill_bigbuf(drv);
  343.     mend -= (4 + 16 + 8 + 512);
  344.     while (length > 0) {
  345.     int trackoffs;
  346.  
  347.     do {
  348.         while (*mbuf++ != 0x4489) {
  349.         if (mbuf >= mend) return;
  350.         }
  351.     } while (*mbuf++ != 0x4489);
  352.  
  353.     odd = getmfmlong(mbuf);
  354.     even = getmfmlong(mbuf+2);
  355.     mbuf += 4;
  356.     id = (odd << 1) | even;
  357.  
  358.     trackoffs = (id & 0xff00) >> 8;
  359.     if (trackoffs > 10) {
  360.         printf("Disk write: weird sector number %d\n", trackoffs);
  361.         continue;
  362.     }
  363.     chksum = odd ^ even;
  364.     for (i=0; i<4; i++) {
  365.         odd = getmfmlong(mbuf);
  366.         even = getmfmlong(mbuf+8);
  367.         mbuf += 2;
  368.  
  369.         dlong = (odd << 1) | even;
  370.         if (dlong)  secwritten = -200;
  371.         chksum ^= odd ^ even;
  372.     }  /* could check here if the label is nonstandard */
  373.     mbuf += 8;
  374.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  375.     if ((((odd << 1) | even) != chksum) ||
  376.         (((id & 0x00ff0000) >> 16) != drv->cyl*2 + side)) {
  377.         write_log ("Disk write: checksum error on sector header\n");
  378.         continue;
  379.     }
  380.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  381.     chksum = (odd << 1) | even;
  382.     secdata = secbuf + 32;
  383.     for (i=0; i<128; i++) {
  384.         odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2;
  385.         dlong = (odd << 1) | even;
  386.         *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff;
  387.         *secdata++ = dlong >> 8; *secdata++ = dlong;
  388.         chksum ^= odd ^ even;
  389.     }
  390.     mbuf += 256;
  391.     if (chksum) {
  392.         write_log ("Disk write: data checksum error\n");
  393.         continue;
  394.     }
  395.     secwritten++;
  396.     fseek(drv->diskfile,
  397.           drv->trackdata[drv->cyl*2 + side].offs + trackoffs*512,
  398.           SEEK_SET);
  399.     fwrite(secbuf+32, sizeof(uae_u8), 512, drv->diskfile);
  400.     }
  401.     drv->buffered_side = 2; /* will force read */
  402.  
  403.     if (secwritten == 0)
  404.     write_log ("Disk write in unsupported format\n");
  405.     if (secwritten < 0)
  406.     write_log ("Disk write: sector labels ignored\n");
  407. }
  408.  
  409.  
  410. static void drive_eject(drive *drv)
  411. {
  412.     if (!drive_empty(drv))
  413.     zfile_close(drv->diskfile);
  414.  
  415.     drv->dskchange = 4;
  416.     drv->dskchange_time = 20;
  417. /*    printf("setting changed bit %d\n", drv-floppy);*/
  418.     drv->diskfile = 0;
  419. }
  420.  
  421. /* We use this function if we have no Kickstart ROM.
  422.  * No error checking - we trust our luck. */
  423. void DISK_ersatz_read (int tr, int sec, uaecptr dest)
  424. {
  425.     int i;
  426.     uae_u8 *dptr = get_real_address(dest);
  427.     fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec*512, SEEK_SET);
  428.     fread (dptr, 1, 512, floppy[0].diskfile);
  429. }
  430.  
  431. void disk_eject(int num)
  432. {
  433.     gui_filename(num, "");
  434.     drive_eject(floppy + num);
  435.     *currprefs.df[num] = *changed_prefs.df[num] = 0;
  436. }
  437.  
  438. void disk_insert(int num, const char *name)
  439. {
  440.     /* just to be sure */
  441.     drive_eject(floppy + num);
  442.     drive_insert(floppy + num, num, name);
  443. }
  444.  
  445. void DISK_check_change (void)
  446. {
  447.     int i;
  448.     static int count = 0;
  449.     count++;
  450.  
  451.     for (i = 0; i < 4; i++) {
  452.     if (strcmp (currprefs.df[i], changed_prefs.df[i]) != 0) {
  453.         if (currprefs.df[i][0] != '\0') {
  454.         drive_eject(floppy + i);
  455.         currprefs.df[i][0] = '\0';
  456.         gui_filename(i, "");
  457.         } else if (floppy[i].dskchange == 1) {
  458.         /* In theory, it should work without the dskchange test.
  459.          * In practice, it doesn't. */
  460.         drive_insert (floppy + i, i, changed_prefs.df[i]);
  461.         } else if (floppy[i].dskchange > 1 && floppy[i].dskchange_time > 0) {
  462.         /* Force the dskchange bit to go to 1 after a given timeout */
  463.         if (--floppy[i].dskchange_time == 0) {
  464.             floppy[i].dskchange = 1;
  465.         }
  466.         }
  467.     }
  468.     }
  469. }
  470.  
  471. int disk_empty(int num)
  472. {
  473.     return drive_empty(floppy + num);
  474. }
  475.  
  476. void DISK_init()
  477. {
  478.     int i;
  479.     for (i = 0; i < 4; i++)
  480.     if (!drive_insert (floppy+i, i, currprefs.df[i]))
  481.         disk_eject (i);
  482.  
  483.     if (disk_empty (0))
  484.     write_log ("No disk in drive 0.\n");
  485. }
  486.  
  487. static int ledstate[] = { 0,0,0,0 };
  488.  
  489. void DISK_select(uae_u8 data)
  490. {
  491.     int step_pulse;
  492.     int dr;
  493.  
  494.     if (selected != ((data >> 3) & 15))
  495.     dskready = 0;
  496.     selected = (data >> 3) & 15;
  497.     side = 1 - ((data >> 2) & 1);
  498.  
  499.     direction = (data >> 1) & 1;
  500.     step_pulse = data & 1;
  501.     if (step != step_pulse) {
  502.     step = step_pulse;
  503.     if (step == 0){
  504.         for (dr = 0; dr < 4; dr++){
  505.         if (!(selected & (1 << dr))) {
  506.             drive_step(floppy + dr);
  507.         }
  508.         }
  509.     }
  510.     }
  511.     for (dr = 0; dr < 4; dr++){
  512.     if (!(selected & (1<<dr))) {
  513.         drive_motor(floppy + dr, data >> 7);
  514.     }
  515.     }
  516.     for (dr = 0; dr < 4; dr++) {
  517.     int state = (!(selected & (1<<dr))) | !floppy[dr].motoroff;
  518.     if (state != ledstate[dr])
  519.         gui_led (dr+1, state);
  520.     ledstate[dr] = state;
  521.     gui_ledstate = (gui_ledstate & ~(1 << (dr + 1))) | (state << (dr + 1));
  522.     }
  523. }
  524.  
  525. uae_u8 DISK_status()
  526. {
  527.     uae_u8 st = 0x3c;
  528.     int dr;
  529.  
  530.     for (dr = 0; dr < 4; dr++){
  531.     drive *drv = floppy + dr;
  532.     if (!(selected & (1 << dr))) {
  533.         if (drive_running(drv)){
  534.         if (dskready) st &= ~0x20;
  535.         dskready = 1;
  536.         } else {
  537.         st &= ~0x20; /* report drive ID */
  538.         }
  539.  
  540.         if (drive_track0 (drv)) { st &= ~0x10; }
  541.         if (drive_writeprotected (drv)) { st &= ~8; }
  542.         if (drv->dskchange) {
  543.         /*printf("changed bit set: %d\n",dr); */
  544.         st &= ~0x4;
  545.         if (drv->dskchange > 1)
  546.             drv->dskchange--;
  547.         }
  548.     }
  549.     }
  550.     return st;
  551. }
  552.  
  553. int DISK_GetData(uae_u16 *mfm,uae_u16 *byt)
  554. {
  555.     int dr;
  556.     for (dr = 0; dr < 4; dr++){
  557.     if (!(selected & (1<<dr))) {
  558.         return drive_get_data (floppy + dr, mfm, byt);
  559.     }
  560.     }
  561.     return 0;
  562. }
  563.  
  564. static uae_u16 mfm_read_buffer[0x4000];
  565. static int mfm_read_length;
  566.  
  567. int DISK_PrepareReadMFM(int length, uae_u16 sync, int use_sync)
  568. {
  569.     int dr;
  570.  
  571.     mfm_read_length = 0;
  572.  
  573.     for (dr = 0; dr < 4; dr++) {
  574.     if (!(selected & (1<<dr))) {
  575.         int time = 0;
  576.         uae_u16 *mfmp = mfm_read_buffer;
  577.         drive *drv = floppy + dr;
  578.         int offset,mfmpos;
  579.  
  580.         drive_fill_bigbuf(drv);
  581.  
  582.         offset = (cycles - drv->last_cycles) / FLOPPY_SPEED;
  583.         mfmpos = (drv->mfmpos + offset) % drv->tracklen;
  584.         drv->last_cycles += offset*FLOPPY_SPEED;
  585.         drv->mfmpos = mfmpos;
  586.         mfmpos++; mfmpos %= drv->tracklen;
  587.         while (drv->bigmfmbuf[mfmpos] != sync && mfmpos != drv->mfmpos && use_sync)
  588.         mfmpos = (mfmpos + 1) % drv->tracklen, time++;
  589.  
  590.         if (drv->bigmfmbuf[mfmpos] != sync && use_sync) {
  591.         write_log ("warning: sync not found on disk read\n");
  592.         return 0;
  593.         } else
  594.         mfmpos++;
  595.  
  596.         mfm_read_length = length;
  597.  
  598.         while (length--) {
  599.         *mfmp++ = drv->bigmfmbuf[mfmpos];
  600.         mfmpos = (mfmpos + 1) % drv->tracklen;
  601.         time++;
  602.         }
  603.  
  604.         return time*FLOPPY_SPEED;
  605.     }
  606.     }
  607.     return 0;
  608. }
  609.  
  610. int DISK_ReadMFM(uaecptr target)
  611. {
  612.     int i;
  613.     uae_u8 *mfmp = get_real_address(target);
  614.  
  615.     if (!chipmem_bank.check(target, mfm_read_length * 2)) {
  616.     write_log ("warning: Bad disk DMA read pointer\n");
  617.     return 0;
  618.     }
  619.  
  620.     for (i = 0; i < mfm_read_length; i++) {
  621.     *mfmp++ = mfm_read_buffer[i] >> 8;
  622.     *mfmp++ = mfm_read_buffer[i];
  623.     }
  624.     return 1;
  625. }
  626.  
  627. void DISK_InitWrite()
  628. {
  629.     mfmwrite = mfmwrbuffer;
  630. }
  631.  
  632. void DISK_WriteData(int length)
  633. {
  634.     int dr;
  635.     for (dr=0;dr<4;dr++){
  636.     if (!(selected & (1<<dr))) {
  637.         drive_write_data(floppy + dr, mfmwrbuffer, length);
  638.     }
  639.     }
  640. }
  641.